// 窗口大小为990*660 其中地面的高度为41 groundHeight总共高度 网的位置在495
wWidth = 990; // 窗口大小
wHeight = 660;
midWidth = 495; // 球网水平位置
groundHeight = 619; // 地面高

//人的高度为619-522 = 97 发球时候羽毛球在下面，发球高度为619-573 = 46 人物可以移动在最左边的限制是89
humanHeight = 522; // 球网高&人中心高
ballHeight = 573; // 发球时球的高度
leftManLimit = 89; // 人能运动到的最左的位置

//球碰到最左边就是反弹
leftLimit = 53; // 左边界，球碰到会反弹
ballLeft = 39; // 发球时球距离左边距离



CLOCK = 0; //控制次数
TIMER = 0; //控制时间

b1 = 0.0;

vvv = 24; //;球的初始速度，需要加一个向量做修正

level = 0;
//是否开启AI
leftAIon = 1;
rightAIon = 1;
leftAIhitted = 0; // 0表示允许击球
rightAIhitted = 0;

theBall = {
	mx: ballLeft, //球的当前水平位置  位置 = 位置 + 速度
	my: ballHeight, //球的当前垂直位置
	mvx: 22, //球的X方向速度  通过速度 = 速度 + 加速度 mvx 大于0的话就向右 小于0就向左
	mvy: -22, //球的Y方向速度  mvy大于0向下，mvy小于向上
	max: 0, //球的X方向加速度
	may: 0, //球的Y方向加速度
	hitGroundTime: 0, //球到地面的次数
	cannotHit: 0, //是否能击到
	deg: 0 //deg弧度
};
man1 = {
	mx: leftManLimit, //角色能移动到的最左侧位置
	my: humanHeight, //角色站立时的中心高度
	mvx: 0, //横向移动速度（X 方向速度），正值向右，负值向左，0 表示静止。
	mvy: 0, //纵向移动速度（Y 方向速度），用于跳跃
	player: 1,
	move: 0, // 0:不动，   1:移动
	hit: 0, // 0是未击球  1是击球
	frame1: 0, //挥拍动作的帧数
	frame2: 0, //腿的移动帧数
	score: 0, //得分
};
man2 = {
	mx: wWidth - leftManLimit - 200, //角色能移动到的最左侧位置
	my: humanHeight, //角色站立时的中心高度
	mvx: 0, //横向移动速度（X 方向速度），正值向右，负值向左，0 表示静止。
	mvy: 0, //纵向移动速度（Y 方向速度），用于跳跃
	player: 2,
	move: 0, //;0:不动，1:向前，-1:向后
	hit: 0, // 0是未击球,1是击球
	frame1: 0, //挥拍动作的帧数，是个倒计时
	frame2: 0, //腿的移动帧数
	score: 0, //得分
};

const canv = document.getElementById('canv');
const ctx = canv.getContext('2d');

//写标题
function drawTitle() {
	ctx.drawImage(images.title, 0, 0, wWidth, wHeight);
}
//写比分
function drawInst() {
	ctx.drawImage(images.inst, 0, 0, wWidth, wHeight);
}
//加载背景
function drawBackground() {
	ctx.drawImage(images.bg, 0, 0, wWidth, wHeight);
}
//选择是否开始
function drawChooseMode() {
	ctx.drawImage(images.start, 0, 0, wWidth, wHeight);
}

function ballDeg() {
	theBall.deg = Math.atan2(theBall.mvy, theBall.mvx); // (x, y) 的极角（弧度制） 算球在飞行过程中 应旋转的角度，使得球的贴图方向与运动轨迹一致
}

function drawImage(img, x, y, width, height) {
	// 如果传入的图片是正的，那么久正常在图像上打印
	if (width > 0) {
		ctx.drawImage(img, x, y, width, height); //
	} else {
		// 如果传入的图片是负的，就说明图片是反的。
		ctx.save(); //将现在的图片保存下来
		ctx.scale(-1, 1); //将图片反转
		ctx.drawImage(img, -width - x, y, width, height); //绘制图片
		ctx.restore(); //放回之前的图像
	}
}
//画羽毛球的轨迹
function drawBall() {
	drawImage2(images.ball, theBall.mx, theBall.my, 52, -52, theBall.deg);
}
//绘制羽毛球
function drawImage2(img, x, y, width, height, deg) {
	ctx.save();
	ctx.translate(x, y);
	ctx.rotate(deg);
	ctx.translate(-x, -y);
	ctx.drawImage(img, x - width / 2, y - height / 2, width, height);
	ctx.restore();
}
//绘制比分
function drawPoint() {
	drawImage(images['_' + score1], 448, 34, 22, 34); //1号玩家比分
	drawImage(images['_' + score2], 518, 34, 22, 34); //2号玩家比分
}

// 画玩家1和2
startingBall = 1; //  ;0:不在发球，1:左边发球，2:右边发球
startingBallPre = 1;

function drawPlayer(who) {
	var now_x, now_y; //人的坐标

	if (who == 1) {
		//人的高度为145，
		drawImage(images.body, man1.mx - 145, man1.my - 88, 246, 213); //绘制人的身体
		drawImage(images.shadow, man1.mx - 145, 434, 246, 213); //绘制人的身体下的阴影 max1.mx就是当前人的位置
		now_x = man1.mx - 145;
		now_y = man1.my - 88;
		switch (man1.frame2) {
			case 0:
				drawImage(images.leg1, now_x, now_y, 246, 213);
				if (man1.move != 0) {
					man1.frame2 = 11;
				}
				break;
			case 1:
				drawImage(images.leg2, now_x, now_y, 246, 213);
				man1.frame2--;
				man1.move = 0;
				break;
			case 11:
				drawImage(images.leg2, now_x, now_y, 246, 213);
				man1.frame2--;
				break;
			case 2:
			case 10:
				drawImage(images.leg3, now_x, now_y, 246, 213);
				man1.frame2--;
				break;
			case 3:
			case 9:
				drawImage(images.leg4, now_x, now_y, 246, 213);
				man1.frame2--;
				break;
			case 4:
			case 8:
				drawImage(images.leg5, now_x, now_y, 246, 213);
				man1.frame2--;
				break;
			case 5:
			case 7:
				drawImage(images.leg6, now_x, now_y, 246, 213);
				man1.frame2--;
				break;
			case 6:
				drawImage(images.leg7, now_x, now_y, 246, 213);
				man1.frame2--;
				break;
		}
		now_x = man1.mx - 140;
		now_y = man1.my - 145;
		if (man1.frame1 > 16 || startingBall == 1) {
			now_y += 57;
			now_x -= 5;
		}
		if (startingBall == 1) {
			drawImage(images.hand9, now_x, now_y, 246, 213);
		} else {
			switch (man1.frame1) {
				case 0:
					drawImage(images.hand1, now_x, now_y, 246, 213);
					break;
				case 1:
					drawImage(images.hand2, now_x, now_y, 246, 213);
					man1.frame1--;
					man1.hit = 0;
					break;
				case 2:
					drawImage(images.hand3, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 3:
					drawImage(images.hand4, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 4:
					drawImage(images.hand5, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 5:
					drawImage(images.hand6, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 6:
					drawImage(images.hand7, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 7:
					drawImage(images.hand8, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
					//下挥拍
				case 21:
					drawImage(images.hand15, now_x, now_y, 246, 213);
					man1.frame1 = 7;
					man1.hit = 0;
					break;
				case 22:
					drawImage(images.hand14, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 23:
					drawImage(images.hand13, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 24:
					drawImage(images.hand12, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 25:
					drawImage(images.hand11, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 26:
					drawImage(images.hand10, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
				case 27:
					drawImage(images.hand9, now_x, now_y, 246, 213);
					man1.frame1--;
					break;
			}
		}
	} else {
		now_x = man2.mx + 145;
		now_y = man2.my - 88;
		drawImage(images.body, now_x, now_y, -246, 213);
		drawImage(images.shadow, now_x, 434, -246, 213);
		switch (man2.frame2) {
			case 0:
				drawImage(images.leg1, now_x, now_y, -246, 213);
				if (man2.move != 0) {
					man2.frame2 = 11;
				}
				break;
			case 1:
				drawImage(images.leg2, now_x, now_y, -246, 213);
				man2.frame2--;
				man2.move = 0;
				break;
			case 11:
				drawImage(images.leg2, now_x, now_y, -246, 213);
				man2.frame2--;
				break;
			case 2:
			case 10:
				drawImage(images.leg3, now_x, now_y, -246, 213);
				man2.frame2--;
				break;
			case 3:
			case 9:
				drawImage(images.leg4, now_x, now_y, -246, 213);
				man2.frame2--;
				break;
			case 4:
			case 8:
				drawImage(images.leg5, now_x, now_y, -246, 213);
				man2.frame2--;
				break;
			case 5:
			case 7:
				drawImage(images.leg6, now_x, now_y, -246, 213);
				man2.frame2--;
				break;
			case 6:
				drawImage(images.leg7, now_x, now_y, -246, 213);
				man2.frame2--;
				break;
		}
		now_x = man2.mx + 140;
		now_y = man2.my - 145;
		if (man2.frame1 > 16 || startingBall == 2) {
			now_y += 57;
			now_x += 5;
		}
		if (startingBall == 2) {
			drawImage(images.hand9, now_x, now_y, -246, 213);
		} else {
			switch (man2.frame1) {
				case 0:
					drawImage(images.hand1, now_x, now_y, -246, 213);
					break;
				case 1:
					drawImage(images.hand2, now_x, now_y, -246, 213);
					man2.frame1--;
					man2.hit = 0;
					break;
				case 2:
					drawImage(images.hand3, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 3:
					drawImage(images.hand4, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 4:
					drawImage(images.hand5, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 5:
					drawImage(images.hand6, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 6:
					drawImage(images.hand7, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 7:
					drawImage(images.hand8, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 21:
					drawImage(images.hand15, now_x, now_y, -246, 213);
					man2.frame1 = 7;
					man2.hit = 0;
					break;
				case 22:
					drawImage(images.hand14, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 23:
					drawImage(images.hand13, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 24:
					drawImage(images.hand12, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 25:
					drawImage(images.hand11, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 26:
					drawImage(images.hand10, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
				case 27:
					drawImage(images.hand9, now_x, now_y, -246, 213);
					man2.frame1--;
					break;
			}
		}

	}
}



//预存图片，因为我们这个是一帧一帧加载的，所以会经常加载图片，但是经常加载图片的话就会卡顿，所以我们需要把这个预存起来。
function loadImages() {
	IMAGE_LOADED = 0;
	var count = 37;
	images = {
		_0: new Image(),
		_1: new Image(),
		_2: new Image(),
		_3: new Image(),
		_4: new Image(),
		_5: new Image(),
		_6: new Image(),
		_7: new Image(),
		ball: new Image(),
		bg: new Image(),
		body: new Image(),
		hand1: new Image(),
		hand2: new Image(),
		hand3: new Image(),
		hand4: new Image(),
		hand5: new Image(),
		hand6: new Image(),
		hand7: new Image(),
		hand8: new Image(),
		hand9: new Image(),
		hand10: new Image(),
		hand11: new Image(),
		hand12: new Image(),
		hand13: new Image(),
		hand14: new Image(),
		hand15: new Image(),
		inst: new Image(),
		leg1: new Image(),
		leg2: new Image(),
		leg3: new Image(),
		leg4: new Image(),
		leg5: new Image(),
		leg6: new Image(),
		leg7: new Image(),
		shadow: new Image(),
		start: new Image(),
		title: new Image(),
	};
	with(images) {
		_0.src = '../img/0.png';
		_1.src = '../img/1.png';
		_2.src = '../img/2.png';
		_3.src = '../img/3.png';
		_4.src = '../img/4.png';
		_5.src = '../img/5.png';
		_6.src = '../img/6.png';
		_7.src = '../img/7.png';
		ball.src = '../img/ball.png';
		bg.src = '../img/bg.jpg';
		body.src = '../img/body.png';
		hand1.src = '../img/hand1.png';
		hand2.src = '../img/hand2.png';
		hand3.src = '../img/hand3.png';
		hand4.src = '../img/hand4.png';
		hand5.src = '../img/hand5.png';
		hand6.src = '../img/hand6.png';
		hand7.src = '../img/hand7.png';
		hand8.src = '../img/hand8.png';
		hand9.src = '../img/hand9.png';
		hand10.src = '../img/hand10.png';
		hand11.src = '../img/hand11.png';
		hand12.src = '../img/hand12.png';
		hand13.src = '../img/hand13.png';
		hand14.src = '../img/hand14.png';
		hand15.src = '../img/hand15.png';
		inst.src = '../img/inst.jpg';
		leg1.src = '../img/leg1.png';
		leg2.src = '../img/leg2.png';
		leg3.src = '../img/leg3.png';
		leg4.src = '../img/leg4.png';
		leg5.src = '../img/leg5.png';
		leg6.src = '../img/leg6.png';
		leg7.src = '../img/leg7.png';
		shadow.src = '../img/shadow.png';
		start.src = '../img/start.png';
		title.src = '../img/title.jpg';
	}
	//检查是否全部图片加载完毕，如果有一个没加入的话IMAGE_LOAD就不会增加，那么到时候就不会加载图片
	for (var p in images) {
		images[p].onload = function() {
			IMAGE_LOADED++;
			if (IMAGE_LOADED == count) {
				imageLoadComplete();
			}
		}
	}
}


function imageLoadComplete() {
	onPaint();
}


readPicture = 0;
drawingTitle = 1; //画标题
drawingInst = 1; //画键盘的操作输入 1开始 0结束
choosingMode = 1; //是否游戏开始 1开始 0结束

function onPaint() {
	if (readPicture == 0) {
		document.body.classList.remove('choosing-mode');
		drawTitle();
		readPicture = 1;
	} else {
		if (drawingTitle == 1) {
			document.body.classList.remove('choosing-mode');
			drawTitle();
		} else if (drawingInst == 1) {
			document.body.classList.remove('choosing-mode');
			drawInst();
		} else if (choosingMode == 1) {
			document.body.classList.add('choosing-mode');
			drawChooseMode();
		} else {
			document.body.classList.remove('choosing-mode');
			drawBackground();
			drawPoint();
			drawPlayer(1);
			drawPlayer(2);
			drawBall();
		}
	}
}




//开始游戏初始化效果
function onBtnStart() {
	man1.mx = leftManLimit;
	man1.my = humanHeight;
	man2.mx = wWidth - leftManLimit - 200;
	man2.my = humanHeight;
	hitGroundTimer = 30;
	someoneWins = 0;
	startingBall = 1;
	startingBallPre = 1;
	leftAIhitted = 0;
	rightAIhitted = 0;
	theBall.hitGroundTime = 0;
	theBall.cannotHit = 0;
	kw = 0;
	ka = 0;
	ks = 0;
	kd = 0;
	kleft = 0;
	kright = 0;
	kup = 0;
	kright = 0;
	score1 = 0;
	score2 = 0;
	CLOCK = 0;
	if (TIMER)
		clearInterval(TIMER);
	TIMER = setInterval(stepOver, 15);
}

function showWinMessageBox(who) {
    // 创建模态窗口元素
    const modal = document.createElement('div');
    modal.className = 'modal fade';
    modal.id = 'winModal';
    modal.tabIndex = '-1';
    modal.setAttribute('aria-labelledby', 'winModalLabel');
    modal.setAttribute('aria-hidden', 'true');
    pre_who = who;
	who = "玩家" + who;
    // 模态窗口内容
	if(rightAIon == 1 && pre_who == 2){
		who = 'AI';
	}
    modal.innerHTML = `
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="winModalLabel">游戏结束</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body text-center">
                    <audio id="winSound" preload="auto">
                        <source src="../mp3/yeyeye.mp3" type="audio/mpeg">
                    </audio>
                    <h4> ${who} 获胜!</h4>
                </div>
                <div class="modal-footer justify-content-center">
                    <button type="button" class="btn btn-primary" data-bs-dismiss="modal">确定</button>
                </div>
            </div>
        </div>
    `;

    // 添加到页面
    document.body.appendChild(modal);
    
    // 初始化模态窗口
    const winModal = new bootstrap.Modal(modal);
    winModal.show();
    
    // 播放胜利音效
    setTimeout(() => {
        const winSound = modal.querySelector('#winSound');
        if (winSound) {
            winSound.play().catch(e => {
                console.log("播放音效失败:", e);
                // 添加备用播放方法
                const audio = new Audio('../mp3/yeyeye.mp3');
                audio.play().catch(err => console.log("备用播放失败:", err));
            });
        }
    }, 300); // 300ms延迟确保模态窗口已渲染
    
    // 模态窗口关闭后自动移除
    modal.addEventListener('hidden.bs.modal', () => {
        modal.remove();
    });
}

function drawOneFrame() {
	if (choosingMode == 1) {
		readPicture = 1;
	}
	onPaint();
}



//球的移动
u1 = 0.37; //;羽毛球下落加速度
u2 = 0.045; //;空气粘滞系数

//mx: ballLeft,    球的当前水平位置
//my: ballHeight,  球的当前垂直位置
//mvx: 22,         //球的X方向速度
//mvy: -22,        //球的Y方向速度
//max: 0,          //球的X方向加速度
//may: 0,          //球的Y方向加速度
function ballMove() {
	//从快到慢的一个过程，先是
	if (startingBall == 0) {

		theBall.max = -theBall.mvx * u2; // X方向的加速度 (空气阻力）
		theBall.may = u1 - theBall.mvy * u2; // Y方向的加速度（重力 + 空气阻力)
		//mvx>0 就向右移动 
		theBall.mvx += theBall.max; // 羽毛球的速度 = 羽毛球的当前速度 加上 羽毛球的加速度（如果羽毛球是在左边，那么mvx小于0就是减速，如果羽毛球是在右边，mvx大于0就是加速)
		theBall.mvy += theBall.may; // 如果羽毛球是在上升的时候当

		ballPreX = theBall.mx;
		theBall.mx += theBall.mvx;
		ballPreY = theBall.my;
		theBall.my += theBall.mvy;
		//羽毛球当前的位置加上球的速度就是球下一帧的位置
		ballDeg();
		checkBallStatus();
	} else {
		//确认左右边发球
		if (startingBall == 1) {
			var ballX = man1.mx;
			ballX += ballLeft;
			if (leftAIon == 0) {
				ballX -= 10;
			}
			theBall.mx = ballX;
			ballX = ballHeight;
			ballX -= humanHeight;
			ballX += man1.my;
			theBall.my = ballX;
		} else {
			var ballX = man2.mx;
			ballX -= ballLeft;
			if (rightAIon == 0) {
				ballX += 10;
			}
			theBall.mx = ballX;
			ballX = ballHeight;
			ballX -= humanHeight;
			ballX += man2.my;
			theBall.my = ballX;
		}
	}
}
//球停止
function ballStop() {
	theBall.my = groundHeight;
	theBall.mvx = 0;
	theBall.mvy = 0;
	theBall.max = 0;
	theBall.may = 0;

	if (someoneWins == 0) {
		hitGroundTimer--;
	}

	if (hitGroundTimer == 0) {
		theBall.hitGroundTime = 0;
		hitGroundTimer = 30;
		theBall.cannotHit = 0;
	} else {
		return;
	}
	startingBall = startingBallPre;
	if (theBall.mx < wWidth / 2) {
		leftAIhitted = 0;
		rightAIhitted = 1;
	} else {
		leftAIhitted = 1;
		rightAIhitted = 0;
	}
}

kw = 0;
ka = 0;
ks = 0;
kd = 0;
kup = 0;
kdown = 0;
kleft = 0;
kright = 0;
kenter = 0;
u3 = 0.55; //;人下落加速度

// 负责更新玩家1和玩家2的位置和速度，处理键盘输入对玩家移动的影响
function manMove() {
	// 保存玩家1和玩家2的当前位置到临时变量，可能用于后续的碰撞检测或其他计算
	man1preX = man1.mx;
	man1preY = man1.my;
	man2preX = man2.mx;
	man2preY = man2.my;
	if (ka == 1 && kd == 0) {// 按下A键(左移)且未按D键,设置向左的速度并标记为移动状态，人物速度均为5.5像素/帧
		man1.mvx = -5.5;
		man1.move = 1;
	} else if (kd == 1 && ka == 0) {
		man1.mvx = 5.5;
		man1.move = 1;
	} else {// 无按键，停止移动
		man1.mvx = 0;
	}
	if (kleft == 1 && kright == 0) {
		man2.mvx = -5.5;
		man2.move = 1;
	} else if (kright == 1 && kleft == 0) {
		man2.mvx = 5.5;
		man2.move = 1;
	} else {
		man2.mvx = 0;
	}
	if (kw == 1 && man1.my == humanHeight) { // 按下W键且玩家1站在地面上
		kw = 0;//重置w键状态
		man1.mvy = 10.5;//设置向上初速度
	}
	if (kup == 1 && man2.my == humanHeight) {
		kup = 0;
		man2.mvy = 10.5;
	}

	man1.mx += man1.mvx;  // 更新玩家1的水平位置
	man2.mx += man2.mvx;  // 更新玩家2的水平位置
	
	man1.mvy -= u3;       // 应用重力加速度到玩家1的垂直速度
	man2.mvy -= u3;       // 应用重力加速度到玩家2的垂直速度
	
	man1.my -= man1.mvy;  // 更新玩家1的垂直位置
	man2.my -= man2.mvy;  // 更新玩家2的垂直位置


	// 防止玩家掉出地面
	if (man1.my > humanHeight) {  // 玩家1低于地面高度
	    man1.my = humanHeight;    // 重置到地面高度
	    man1.mvy = 0;             // 垂直速度归零
	}
	if (man2.my > humanHeight) {  // 玩家2低于地面高度
	    man2.my = humanHeight;    // 重置到地面高度
	    man2.mvy = 0;             // 垂直速度归零
	}

	// 玩家1的左右边界
	if (man1.mx < leftManLimit) man1.mx = leftManLimit;                     // 不能超出左边界
	if (man1.mx > midWidth - leftLimit) man1.mx = midWidth - leftLimit;     // 不能超过中线左侧限制
	
	// 玩家2的左右边界
	if (man2.mx > wWidth - leftManLimit) man2.mx = wWidth - leftManLimit;   // 不能超出右边界
	if (man2.mx < midWidth + leftLimit) man2.mx = midWidth + leftLimit;     // 不能超过中线右侧限制
	
	// 发球时的额外限制
	if (startingBall == 1 && man1.mx > 280) man1.mx = 280;                  // 玩家1发球时不能太靠右
	if (startingBall == 2 && man2.mx < wWidth - 280) man2.mx = wWidth - 280; // 玩家2发球时不能太靠左
}

function checkBallStatus() {
	if (theBall.my > groundHeight) ballHitGround(); //击打到地板
	if (theBall.mx > wWidth - leftLimit || theBall.mx < leftLimit) ballHitWall(); //击打到墙
	if ((theBall.mx >= midWidth) ^ (ballPreX >= midWidth)) { //击打到网
		if (theBall.my >= humanHeight && theBall.my <= groundHeight && ballPreY >= humanHeight && ballPreY <=
			groundHeight) {
			ballHitNet();
		}
	}
	if (theBall.hitGroundTime > 3) ballStop();
}
//击打到网,速度就应该降低并且向击打到网的那一边移动
//速度：
//mvx表示了球的方向速度mvx大于0就是向右飞行，如果mvx小于0就是向左飞行
function ballHitNet() {
	theBall.mvx /= -2; //如果球是在左边的话，打到网之后，球的速度就除以-2这样子球的速度变慢，并且往左边飞行，同理如果球在右边的话，打到网
	theBall.mx -= wWidth;
	theBall.mx *= -1;
}
//检查是否击打到球
function checkHitBall() {
	if (ks == 1) {
		if (startingBall == 1) {
			startingBall = 0;
			return;
		}
		ks = 0;
		if (man1.hit == 0) {
			if (man1.my < theBall.my) {
				man1.frame1 = 27;
			} else {
				man1.frame1 = 7;
			}
			man1.hit = 1;
		}
		if (theBall.cannotHit == 0) {
			if (getSpeed(1) != 0 && theBall.mx < midWidth) {
				manHitBall(man1.mx, man1.my, theBall.mx, theBall.my, vvv);
			}
		}
	}

	if (kdown == 1) {
		if (startingBall == 2) {
			startingBall = 0;
			return;
		}
		kdown = 0;
		if (man2.hit == 0) {
			if (man2.my < theBall.my) {
				man2.frame1 = 27;
			} else {
				man2.frame1 = 7;
			}
			man2.hit = 1;
		}
		if (theBall.cannotHit == 0) {
			if (getSpeed(2) != 0 && theBall.mx > midWidth) {
				manHitBall(man2.mx, man2.my, theBall.mx, theBall.my, vvv);
			}
		}
	}
}
// //球的轨迹弧度
// function hitBallDegree(sx, sy, v0, deg) {
// 	hitBall(sx, sy, v0 * cos(-deg), v0 * sin(-deg));
// }
//计算距离
function getDistance(x1, y1, x2, y2) {
	return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
// 根据球和击球者的距离计算有效速度
function getSpeed(who) {
	const MIN_DISTANCE = 45; // 最小有效击球距离
	const MAX_DISTANCE = 150; // 最大有效击球距离
	const VERTICAL_WEIGHT = 90; // 垂直距离权重
	const HORIZONTAL_WEIGHT = 79; // 水平距离权重

	let player, isPlayer1;

	if (who === 1) {
		player = man1;
		isPlayer1 = true;
	} else {
		player = man2;
		isPlayer1 = false;
	}

	// 检查是否在扇形盲区内（后方不可击球区域）
	const isBallBehind = isPlayer1 ?
		(theBall.mx < player.mx) : //如果是玩家一，球在人的后面则不可以击球 
		(theBall.mx > player.mx); //如果是玩家二，球在人的后面则不可以击球


	if (isBallBehind) {
		const dis_x = Math.abs(player.mx - theBall.mx);
		const dis_y = Math.abs(theBall.my - player.my);
		// 扇形盲区判断: 垂直距离×90 < 水平距离×79 → 无效击球
		if (dis_y * VERTICAL_WEIGHT < dis_x *
			HORIZONTAL_WEIGHT) { // Y/X < 90/79设定的范围 tan(0) < 79/90 相当于在0到41的范围内是不可以击球的，只有球在玩家的前面并且处于大于41的时候才可以正常的击球
			return 0;
		}
	}

	// 计算球与玩家的距离
	const distance = getDistance(
		player.mx, player.my,
		theBall.mx, theBall.my
	);

	// 判断是否在有效击球距离内
	// 确定一个扇形 确认球在那个扇形的区间内 min_distance是内部半径，max_distance是外部半径
	if (distance >= MIN_DISTANCE && distance <= MAX_DISTANCE) {
		return (vvv * distance) / 120; // 速度 = 基础系数 * 距离 / 120
	}

	return 0; // 默认返回0
}

function manHitBall(playerX, playerY, ballX, ballY, Speed) {

	const dx = ballX - playerX;
	const dy = ballY - playerY;
	const distanceSq = dx * dx + dy * dy;

	// 分解速度分量
	// FaX = F * COSθ
	// FbX = F * sinθ
	let velX = Speed * Math.abs(dy) / Math.sqrt(distanceSq);
	let velY = Speed * Math.abs(dx) / Math.sqrt(distanceSq);

	// 调整方向
	// 计算dx大于0的话，就是说明球在玩家右边，小于0的话，就是说明在玩家左边
	// dy小于0的话，说明球在玩家上面，dx大于0的话，球在玩家下面
	//  velX 大于0就是向右 小于0就是向左
	//  velY 小于0就是向上 大于0就是向下



	// 左边玩家击球，球在玩家右边vel,dx大于0 velX不变 如果球在左边 velX取反，因为球还是要往右飞
	// 右边玩家击球，球在玩家右边vel,dx小于0 velX取反 如果球在左边 velX不变，因为球还是要往左飞
	velX = dx > 0 ? velX : -velX;
	velY = dy < 0 ? -velY : velY;


	// 确保球飞向对方场地
	const isLeftPlayer = playerX < midWidth;
	if ((isLeftPlayer && velX < 0) || (!isLeftPlayer && velX > 0)) {
		velX = -velX;
		velY = -velY;
	}

	//左半场玩家 (ManX < midWidth)：
	//velX  += 12：让球更易飞向右半场（防止击球无力）
	//velY -= 12：降低球飞行高度（避免过高抛物线）
	//右半场玩家 (ManX > midWidth)：
	//velX -= 12：让球更易飞向左半场
	//velY -= 12：同样降低高度（保持对称性）
	// 添加场地位置修正
	
	let positionAdjustment;
	if (isLeftPlayer) {
		positionAdjustment = 12; 
		velX += positionAdjustment;
		velY -= positionAdjustment;
	} else {
		if (rightAIon == 1) {
			if(level == 0 || level == 1) positionAdjustment = Math.floor(Math.random() * 3) + 2; //(2-5)
			if(level == 2) positionAdjustment  = Math.floor(Math.random() * 3) + 3;//(5-13)
		} else {
			positionAdjustment = 12;
		}
		velX -= positionAdjustment;
		velY -= positionAdjustment;
	}


	// 处理低球特殊击球
	// 如果是低球，忽略前面的全部，直接给他一个初始速度
	if (ballY > playerY) {
		const powerHitSpeed = 29;
		if (isLeftPlayer) {
			velX = powerHitSpeed;
		} else {
			velX = -powerHitSpeed;
		}
		velY = -powerHitSpeed;
	}
	hitBall(ballX, ballY, velX, velY);
}

//击打球
function hitBall(ballX, ballY, speedX, speedY) {
	theBall.mx = ballX;
	theBall.my = ballY;
	theBall.mvx = speedX;
	theBall.mvy = speedY;
}
//球碰到墙
function ballHitWall() {
	// 如果球碰到右边 球就往左飞，那么让他的速度取反，因为这里的mvx是用于决定方向的,mx就是相当于它的位置往下
	if (theBall.mx > wWidth - leftLimit) {
		theBall.mvx *= -1;
		theBall.mx -= 2 * (wWidth - leftLimit);
		theBall.mx *= -1;
	}
	// 如果球碰到左边 
	if (theBall.mx < leftLimit) {
		theBall.mvx *= -1;
		theBall.mx -= 2 * leftLimit;
		theBall.mx *= -1;
	}
}
//球碰到地板
function ballHitGround() {
	theBall.mvy *= -1;
	theBall.mvy /= 4;
	theBall.mvx /= 2;

	theBall.my -= 2 * groundHeight;
	theBall.my *= -1;

	theBall.hitGroundTime++;
	theBall.cannotHit = 1;
	if (theBall.hitGroundTime == 1) {
		if (ballPreX < midWidth) {
			man2.score++;
			score2++;
		} else {
			man1.score++;
			score1++;
		}
	}
	if (theBall.hitGroundTime != 1) return;
	if (ballPreX < wWidth / 2) {
		startingBallPre = 2;
	} else {
		startingBallPre = 1;
	}
}

function rightAIconsider() {
	// · 写AI也就是根据当前各个物体的状态参数等，确定要完成的键盘操作
	// · 右边AI可用的键盘操作有kup/kdown/kleft/kright
	// · 按下按键就是把kup等等变成1，抬起就是变成0
	var man2_leftboundary, //ai左边限制
		man2_rightboundary, //ai右边限制，存储 AI移动的右边界 或 球的位置偏移量
		ball_boundary, //球偏移量(检测球边界)
		temp_dis; //计算球和人距离
	//高球起跳
	var ball_height;
	if (theBall.mx < midWidth) { //球在左半场时将ai击球状态置为0，允许再次击球
		rightAIhitted = 0;
	}
	// 1. 首先检查是否需要跳起扣杀（高球判定）
	if(level != 0){
		if (rightAIhitted == 0) {
			ball_height = man2.my - 80; // 高球判定点（头顶上方80像素）
			temp_dis = getDistance(theBall.mx, theBall.my, man2.mx, ball_height);
	
			// 如果球在高球有效范围内，优先触发起跳
			if (temp_dis < 110 && temp_dis > 45) {
				kup = 1; // 执行起跳动作
			}
		}
	}
	


	//这部分是ai移动逻辑，ai是根据球的位置进行移动
	if (theBall.mx < midWidth) { //球在左半场时，ai位置会被限制在右半场中线位置，可进行微调
		man2_leftboundary = midWidth * 1.5 - 30;
		man2_rightboundary = midWidth * 1.5 + 30;
		if (man2.mx < man2_leftboundary) { // ai位置太靠左边，就向右移动
			kleft = 0;
			kright = 1;
		} else if (man2.mx > man2_rightboundary) { // 否则向左移动
			kleft = 1;
			kright = 0;
		} else {
			kleft = 0;
			kright = 0;
		}
	} else { // 球在右半场，ai就根据球的位置进行定位
		man2_leftboundary = man2.mx - 30;
		man2_rightboundary = man2.mx + 30;
		ball_boundary = theBall.mx + 50;
		if (man2_leftboundary > ball_boundary) { //球在人左边
			kleft = 1;
			kright = 0;
		} else if (man2_rightboundary < ball_boundary) { //球在人右边
			kleft = 0;
			kright = 1;
		} else {
			kleft = 0;
			kright = 0;
		}
	}
	// 击球
	if (rightAIhitted == 0) {
		temp_dis = getDistance(theBall.mx, theBall.my, man2.mx, man2.my);
		if (temp_dis < 110 && temp_dis > 45) {
				kdown = 1;
				rightAIhitted = 1;
			
		}
	} else {
		kup = 0;
		return;
	}
}
function nextLevel(level){
	const modal = document.createElement('div');
    modal.className = 'modal fade';
    modal.id = 'NextModal';
    modal.tabIndex = '-1';
    modal.setAttribute('aria-labelledby', 'winModalLabel');
    modal.setAttribute('aria-hidden', 'true');
    modal.innerHTML = `
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body text-center">
                    <h4> 进入第${level + 1}关</h4>
                </div>
                <div class="modal-footer justify-content-center">
                    <button type="button" class="btn btn-primary" data-bs-dismiss="modal">确定</button>
                </div>
            </div>
        </div>
    `;

    // 添加到页面
    document.body.appendChild(modal);
    
    // 初始化模态窗口
    const winModal = new bootstrap.Modal(modal);
    winModal.show();
    
    // 模态窗口关闭后自动移除
    modal.addEventListener('hidden.bs.modal', () => {
        modal.remove();
    });
}

function stepOver() {
	CLOCK++;
	drawOneFrame();
	ballMove();
	manMove();
	checkHitBall();
	if (rightAIon == 1) rightAIconsider();

	if (man1.score == 7) {
		man1.score = 0;
		man2.score = 0;
		someoneWins = 1;
		if(rightAIon == 1){
			if(level < 2){
				// alert("进入第" + (level + 2 )+ "关");
				nextLevel(level+1);
				level = (level + 1 )%3;
				onBtnStart();
			}else if(level == 2){
				const currentUser = JSON.parse(localStorage.getItem('currentUser'));
				if (currentUser) {
				    // 获取或初始化胜利记录
				    const winRecords = JSON.parse(localStorage.getItem('winRecords')) || [];
				    
				    // 查找用户是否已有记录
				    const existingRecordIndex = winRecords.findIndex(record => 
				        record.username === currentUser.username
				    );
				    
				    if (existingRecordIndex !== -1) {
				        // 更新现有记录
				        winRecords[existingRecordIndex].wins = (winRecords[existingRecordIndex].wins || 0) + 1;
				        winRecords[existingRecordIndex].lastWin = new Date().toISOString();
				    } else {
				        // 创建新记录
				        winRecords.push({
				            username: currentUser.username,
				            avatar: currentUser.avatar,
				            wins: 1,
				            lastWin: new Date().toISOString()
				        });
				    }
				    
				    // 按胜利次数排序
				    winRecords.sort((a, b) => b.wins - a.wins);
				    
				    // 保存到localStorage
				    localStorage.setItem('winRecords', JSON.stringify(winRecords));
				    
				    // 更新当前用户的本地数据（如果需要）
				    currentUser.win = winRecords.find(record => 
				        record.username === currentUser.username
				    )?.wins || 0;
				    localStorage.setItem('currentUser', JSON.stringify(currentUser));
				}
				showWinMessageBox(1);
				setTimeout(function() {
					choosingMode = 1;
					drawChooseMode();
				}, 3000);
			}
			
		}else{
			showWinMessageBox(1);
			setTimeout(function() {
				choosingMode = 1;
				drawChooseMode();
			}, 3000);

		}
		
	}
	
	if (man2.score == 7) {
		man1.score = 0;
		man2.score = 0;
		someoneWins = 1;
		showWinMessageBox(2);
		setTimeout(function() {
			choosingMode = 1;
			drawChooseMode();
		}, 3000);
		
		
	}
}
flag = 0
const p1vsp2 = document.getElementById("p1vsp2")
p1vsp2.addEventListener('mouseup', function(e) {
	if (flag == 1) {
		leftAIon = 0;
		rightAIon = 0;
		choosingMode = 0;
		onBtnStart();
	}
});
const p1vsai = document.getElementById("p1vsai")
p1vsai.addEventListener('mouseup', function(e) {
	if (flag == 1) {
		leftAIon = 0;
		rightAIon = 1;
		choosingMode = 0;
		onBtnStart();
	}
});
canv.addEventListener('mouseup', function(e) {
	if (drawingTitle == 1) {
		drawingTitle = 0;
		onPaint();
		return;
	}
	if (drawingInst == 1) {
		drawingInst = 0;
		flag = 1;
		onPaint();
		return;
	}
	if (choosingMode == 0) {
		return;
	}

})


document.addEventListener('keydown', function(e) {
	if (['KeyW', 'KeyS', 'KeyA', 'KeyD', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.code)) {
        e.preventDefault();
    }
	if (leftAIon == 0) {
		switch (e.code) {
			case 'KeyW':
				kw = 1;
				break;
			case 'KeyS':
				ks = 1;
				break;
			case 'KeyA':
				ka = 1;
				break;
			case 'KeyD':
				kd = 1;
				break;
		}
	}
	if (rightAIon == 0) {
		switch (e.code) {
			case 'ArrowUp':
				kup = 1;
				break;
			case 'ArrowDown':
				kdown = 1;
				break;
			case 'ArrowLeft':
				kleft = 1;
				break;
			case 'ArrowRight':
				kright = 1;
				break;
		}
	}
});

document.addEventListener('keyup', function(e) {
	// console.log(e);
	if (leftAIon == 0) {
		switch (e.code) {
			case 'KeyW':
				kw = 0;
				break;
			case 'KeyS':
				ks = 0;
				break;
			case 'KeyA':
				ka = 0;
				break;
			case 'KeyD':
				kd = 0;
				break;
		}
	}
	if (rightAIon == 0) {
		switch (e.code) {
			case 'ArrowUp':
				kup = 0;
				break;
			case 'ArrowDown':
				kdown = 0;
				break;
			case 'ArrowLeft':
				kleft = 0;
				break;
			case 'ArrowRight':
				kright = 0;
				break;
		}
	}
});
document.addEventListener('DOMContentLoaded', function() {
	// 1. 加载图片
	loadImages();
})
